package com.youlu.campus.activity.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.activity.entity.UserActivityQuantityRecord;
import com.youlu.campus.activity.service.ActivityInfoService;
import com.youlu.campus.activity.service.ActivityTaskInfoService;
import com.youlu.campus.activity.service.UserActivityQuantityRecordService;
import com.youlu.campus.activity.service.UserActivityService;
import com.youlu.campus.activity.service.UserActivityTaskRankingService;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.integral.UserIntegralBase;
import com.youlu.campus.base.interactive.vo.ActivitySignUpRequest;
import com.youlu.campus.common.enums.PlatformEnum;

import com.youlu.campus.common.utils.RedisKeyUtil;
import com.youlu.campus.common.utils.TimeUtils;
import com.youlu.campus.entity.ActivityFeedInfo;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.ActivityOrganizerInfo;
import com.youlu.campus.entity.ActivityTaskInfo;
import com.youlu.campus.entity.ActivityTaskRule;
import com.youlu.campus.entity.OrganizerRankingList;
import com.youlu.campus.entity.UniversityInfo;
import com.youlu.campus.entity.UserActivityPointDetail;
import com.youlu.campus.entity.UserIntegralPO;
import com.youlu.campus.entity.UserInviteRecord;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.UserParticipateActivityInfo;
import com.youlu.campus.entity.UserParticipateActivityTaskInfo;
import com.youlu.campus.entity.UserWeekActivityTaskRanking;
import com.youlu.campus.entity.VO.req.UserQaMqMessageReq;
import com.youlu.campus.entity.VO.res.ActivitySignUpRes;
import com.youlu.campus.entity.data.ActivityUserStatistics;
import com.youlu.campus.entity.data.DayActivityJoinRecord;
import com.youlu.campus.entity.data.HourActivityJoinRecord;
import com.youlu.campus.entity.enums.TaskBizType;
import com.youlu.campus.service.activity.ActivityChannelStatisticsService;
import com.youlu.campus.service.activity.ActivityTaskRuleService;
import com.youlu.campus.service.activity.UserParticipateActivityInfoService;
import com.youlu.campus.service.activity.impl.PlatformOtherActivityService;
import com.youlu.campus.service.aomen.AoMenService;
import com.youlu.campus.service.data.ActivityDataService;
import com.youlu.campus.service.data.ActivityUserStatisticsService;
import com.youlu.campus.service.data.impl.UserQaMQService;
import com.youlu.campus.service.english.CompetitionQaInfoService;
import com.youlu.campus.service.feed.ActivityFeedInfoService;
import com.youlu.campus.service.integral.UserIntegralService;
import com.youlu.campus.service.organizer.ActivityOrganizerInfoService;
import com.youlu.campus.service.ranking.UniversityActivityRankingService;
import com.youlu.campus.service.ranking.UserActivityPointDetailService;
import com.youlu.campus.service.ranking.UserActivityPointRankingProvinceService;
import com.youlu.campus.service.university.UniversityService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.visitor.VisitorUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户参与活动 服务
 *
 * @Description:
 * @Author: su
 * @Date: 2025/7/30
 */
@Slf4j
@Service
public class UserActivityServiceImpl implements UserActivityService {

    @Autowired
    private MongoTemplate mongoTemplate;


    @Autowired
    private VisitorUserService visitorUserService;

    @Autowired
    private UserIntegralService userIntegralService;

    @Autowired
    private ActivityOrganizerInfoService activityOrganizerInfoService;

    @Autowired
    private UniversityService universityService;

    @Autowired
    private ActivityTaskRuleService activityTaskRuleService;

    @Autowired
    private ActivityDataService activityDataService;

    @Autowired
    private UserParticipateActivityInfoService userParticipateActivityInfoService;

    @Autowired
    private PlatformOtherActivityService platformOtherActivityService;

    @Autowired
    private UserQaMQService userQaMQService;

    @Autowired
    private ActivityChannelStatisticsService activityChannelStatisticsService;

    @Autowired
    private ActivityUserStatisticsService activityUserStatisticsService;

    @Autowired
    private ActivityFeedInfoService activityFeedInfoService;

    @Autowired
    private UserActivityPointDetailService userActivityPointDetailService;

    @Autowired
    public CompetitionQaInfoService competitionQaInfoService;

    @Autowired
    private UniversityActivityRankingService universityActivityRankingService;

    @Autowired
    private com.youlu.campus.service.course.UserActivityService userActivityService;

    @Autowired
    private UserActivityPointRankingProvinceService userActivityPointRankingProvinceService;

    @Lazy
    @Autowired
    private UserInfoExtendService userInfoExtendService;

    @Autowired
    private AoMenService aoMenService;

    @Resource(name = "masterMongoTemplate")
    private MongoTemplate masterMongoTemplate;

    @Autowired
    private ActivityInfoService activityInfoService;

    @Autowired
    private UserActivityTaskRankingService userActivityTaskRankingService;

    @Autowired
    private UserActivityQuantityRecordService userActivityQuantityRecordService;

    @Autowired
    private ActivityTaskInfoService activityTaskInfoService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 参加活动
     *
     * @param request
     * @param userPO
     * @return
     */
    @Override
    public ActivitySignUpRes signUpActivity(ActivitySignUpRequest request, UserPO userPO) {
        log.info("signUpActivity 用户参加活动 request:{}", JSON.toJSONString(request));
        if (PlatformEnum.QQ_H5.getValue().equals(request.getPlatform())) {
            throw new BusinessException("QQ平台暂不支持活动报名");
        }
        String activityId = request.getActivityId();//活动id
        String userId = request.getUserId(); //用户id
        //获取 redis同步锁
        String lockKey = RedisKeyUtil.getActivitySignUpLock(activityId, userId);
        boolean b = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
        log.info("signUpActivity 用户参加活动 获取 redis锁key:{},b:{}", lockKey, b);
        if (!b) {
            throw new BusinessException("请勿频繁操作,请稍后重试");
        }
        //获取活动信息
        ActivityInfo activityInfo = activityInfoService.findById(activityId);
        if (Objects.isNull(activityInfo)) {
            log.error("signUpActivity activity is null id:{}", activityId);
            throw new BusinessException("活动不存在");
        }
        Date date = new Date();
        if (date.before(activityInfo.getStartTime())) {
            log.error("signUpActivity activity is not start id:{}, startTime:{}", activityId, activityInfo.getStartTime());
            throw new BusinessException("活动未开始!");
        }
        if (date.after(activityInfo.getEndTime())) {
            log.error("signUpActivity activity is end id:{}, endTime:{}", activityId, activityInfo.getEndTime());
            throw new BusinessException("活动已经结束!");
        }
        //查询活动邀请任务  TaskBizType.INVITE
        ActivityTaskInfo taskInfo = activityTaskInfoService.findActivityTaskInfo(activityId, TaskBizType.INVITE);
        if (Objects.isNull(taskInfo)) {
            log.error("signUpActivity ActivityTaskInfo INVITE is null id:{}", activityId);
            throw new BusinessException("该活动没有配置邀请任务");
        }
        //获取用户参与 活动实体类  判断用户是否 已经报名
        UserParticipateActivityInfo userParticipateActivityInfo = userParticipateActivityInfoService.findBy(activityId, userId);
        log.info("signUpActivity 用户参与活动实体类 userParticipateActivityInfo:{}", JSON.toJSONString(userParticipateActivityInfo));
        if (Objects.nonNull(userParticipateActivityInfo) && Boolean.TRUE.equals(userParticipateActivityInfo.getJoined())) {
            log.info("signUpActivity 用户已经参与该活动,请不要重复报名 activityId:{},userId:{}", activityId, userId);
            ActivitySignUpRes res = new ActivitySignUpRes();
            res.setActivityId(activityId);
            res.setCsDetail(activityInfo.getAfterSignUpCsDetail());
            return res;
        }
        //判断手机号是否已经参与活动  一个手机号只能报名一次
        if (StringUtils.isNotBlank(request.getMobile())) {
            log.info("signUpActivity 手机号唯一校验 mobile:{}", request.getMobile());
            UserParticipateActivityInfo byMobile = userParticipateActivityInfoService.findByMobile(activityId, request.getMobile(), true);
            log.info("signUpActivity 手机号唯一校验 :{}", JSONObject.toJSONString(byMobile));
            if (Objects.nonNull(byMobile) && Boolean.TRUE.equals(byMobile.getJoined()) && !byMobile.getUserId().equals(userId)) {
                throw new BusinessException("当前手机号已报名,请更换其他手机号");
            }
        }
        //获取大学信息
        UniversityInfo universityInfo = this.getUniversityInfo(request, activityInfo.getSignUpInputUniversity());
        if (Objects.isNull(universityInfo)) {
            log.error("signUpActivity getUniversityInfo universityInfo is null universityId:{},s:{}", request.getUniversityId(), activityInfo.getSignUpInputUniversity());
            throw new BusinessException("获取学校信息失败,请稍后重试");
        }
        request.setUniversityId(universityInfo.getId());
        request.setUniversityName(universityInfo.getName());
        request.setProvince(universityInfo.getProvince());

        // 更新用户信息
        this.updateUserInfo(request, userPO, universityInfo);

        //更新 用户参与活动实体类
        userParticipateActivityInfo = this.saveUserParticipateActivityInfo(userParticipateActivityInfo, request, userPO, activityInfo);

        //添加积分 用户活动积分
        this.addUserIntegral(userId, 1, "参与活动获得1国青豆", activityId, UserIntegralBase.ACTIVITY_BIZ_TYPE);

        //更新 活动 累计报名人数   redis 缓存
        userParticipateActivityInfoService.increJoinedCount(activityInfo.getId(), 1L);

        // 更新活动 活动用户统计信息
        this.updateActivityUserStatistics(activityId, userPO.getCreatedTime(), activityInfo.getStartTime());

        // 更新 报名用户 高校排行榜
        this.updateUniversityTaskAllRanking(userPO, activityId);

        //创建活动动态详情
        this.createActivityFeedInfo(activityId, taskInfo.getId(), userPO);

        // 创建大赛任务动态详情
        ActivityTaskInfo taskInfoSale = activityTaskInfoService.findActivityTaskInfo(activityId, TaskBizType.SALES);
        if (Objects.nonNull(taskInfoSale)) {
            this.createActivityFeedInfo(activityId, taskInfoSale.getId(), userPO);
        }

        // 更新邀请人 相关信息
        this.updateInvitedByUser(request, userPO, taskInfo, activityInfo, userParticipateActivityInfo);

        // 更新报名统计  redis缓存
        userActivityService.addRegisterActivityNum(activityInfo.getId(), 1);

        //更新活动报名渠道统计
        activityChannelStatisticsService.setSignUpChannel(activityInfo.getId(), request.getChannelCode());

        //推送短信
        if (StringUtils.isNotBlank(request.getMobile())) {
            aoMenService.doPushUserPhone(request.getMobile(), request.getActivityId(), userId);
        }

        //更新承办单位榜单
        if (Boolean.TRUE.equals(activityInfo.getHasOrganizer())) {
            this.updateOrganizer(activityInfo.getId(), userPO, request.getPlatform(), request.getAppId());
        }

        //更新活动 日/时 参与人数
        this.updateActivityJoinNum(activityInfo.getId(), 1);

        //分数及格  并且 没有累加贡献值  && 先答题后报名模式 && 答题次数 >0   && 获取证书是否累加为true
        if (userParticipateActivityInfo.getCurrentQaScore().compareTo(userParticipateActivityInfo.getPassQaScore()) != -1
                && !userParticipateActivityInfo.getAccumulateQ()
                && activityInfo.getQaMode().equals("0")
                && userParticipateActivityInfo.getReTryQaNum() > 0
                && activityInfo.getAccumulate()) {

            ActivityTaskRule taskRule = activityTaskRuleService.find(activityInfo.getId(), TaskBizType.QA.name());
            if (Objects.nonNull(taskRule)) {
                if ("h5++".equals(activityInfo.getType())) {
                    //增加活力值和活力值记录
                    UserActivityPointDetail userActivityPointDetail = new UserActivityPointDetail();
                    userActivityPointDetail.setAction("add");
                    userActivityPointDetail.setActivityId(activityInfo.getId());
                    userActivityPointDetail.setBizDesc("报名成功");
                    userActivityPointDetail.setComments("报名成功" + taskRule.getPoints().intValue());
                    userActivityPointDetail.setBizType("qa");
                    userActivityPointDetail.setOptDate(new Date());
                    userActivityPointDetail.setPoints(taskRule.getPoints().intValue());
                    userActivityPointDetail.setUserId(userPO.getId());
                    userActivityPointDetail.setUserPO(userPO);
                    userActivityPointDetailService.create(userActivityPointDetail);
                    //增加省排行榜
                    userActivityPointRankingProvinceService.updatePoint(userPO, activityInfo.getId(), taskRule.getPoints().intValue());
                } else {
                    // 更新 用户 贡献值榜单
                    taskInfo.setPoints(taskRule.getPoints());//换成  任务规则 贡献值
                    userActivityTaskRankingService.saveQuantity(userPO, taskInfo, TaskBizType.QA);
                }
                userParticipateActivityInfo.setAccumulateQ(true);
            }
        }
        mongoTemplate.save(userParticipateActivityInfo);

        //发送用户 报名信息
        sendUserBaoMingMsg(userParticipateActivityInfo);

        //创建 活动报名返回结果
        ActivitySignUpRes res = getActivitySignUpRes(activityInfo, userParticipateActivityInfo);
        return res;
    }

    /**
     * 发送用户报名信息
     *
     * @param userParticipateActivityInfo
     */
    private void sendUserBaoMingMsg(UserParticipateActivityInfo userParticipateActivityInfo) {
        try {
            UserQaMqMessageReq userQaMqMessageReq = new UserQaMqMessageReq();
            userQaMqMessageReq.setUserId(userParticipateActivityInfo.getUserId());
            userQaMqMessageReq.setUserName(userParticipateActivityInfo.getName());
            userQaMqMessageReq.setActivityId(userParticipateActivityInfo.getActivityId());
            userQaMQService.sendUserBaoMing(userQaMqMessageReq);
        } catch (Exception e) {
            log.error("用户->{} 报名活动->{}同步消息失败", userParticipateActivityInfo.getMobile(), userParticipateActivityInfo.getActivityId(), e);
        }
    }

    /**
     * 更新邀请人相关信息
     *
     * @param request
     * @param userPO
     * @param taskInfo
     * @param activityInfo
     */
    private void updateInvitedByUser(ActivitySignUpRequest request,
                                     UserPO userPO,
                                     ActivityTaskInfo taskInfo,
                                     ActivityInfo activityInfo,
                                     UserParticipateActivityInfo userParticipateActivityInfo) {
        try {
            //活动id
            String activityId = request.getActivityId();
            //用户id
            String userId = request.getUserId();
            //查询邀请记录
            UserInviteRecord record = this.getInvitedRecord(userId, activityId, taskInfo.getId());
            log.info("updateInvitedByUser 用户被邀请记录 record:{}", JSON.toJSONString(record));
            if (Objects.isNull(record) || StringUtils.isBlank(record.getInvitedByUserId()) || Boolean.TRUE.equals(record.getJoinStatus())) {
                log.error("updateInvitedByUser 用户未被邀请/已被邀请过 :{}, :{}", request.getPlatform(), request.getAppId());
                return;
            }
            //获取邀请人信息
            UserPO invitedByUser = visitorUserService.getUser(record.getInvitedByUserId());
            if (Objects.isNull(invitedByUser)) {
                log.error("updateInvitedByUser 邀请人用户信息 is null :{}, :{}, :{}", request.getPlatform(), request.getAppId(), record.getInvitedByUserId());
                return;
            }

            //新增 邀请人 积分
            this.addUserIntegral(record.getInvitedByUserId(), 100, "邀请新用户获取100国青豆", activityId, UserIntegralBase.INVITE_BIZ_TYPE);
            //更新 邀请人 贡献值
            //获取 学校
            if (StringUtils.isBlank(invitedByUser.getUniversityId())) {
                UserParticipateActivityInfo invitedByUserParticipateActivityInfo = userParticipateActivityInfoService.findBy(activityId, invitedByUser.getId());
                if (invitedByUserParticipateActivityInfo != null && StringUtils.isNotBlank(invitedByUserParticipateActivityInfo.getUniversityId())) {
                    //获取 邀请人 参与活动信息
                    UniversityInfo universityInfo = universityService.get(invitedByUserParticipateActivityInfo.getUniversityId());
                    invitedByUser.setUniversityId(universityInfo.getId());
                    invitedByUser.setUniversityName(universityInfo.getName());
                    invitedByUser.setProvince(universityInfo.getProvince());
                    invitedByUser.setUniversityLogo(universityInfo.getLogo());
                    visitorUserService.updateUser(invitedByUser);
                }
            }
            //更新 邀请人 排行榜
            this.updateInviteRank(invitedByUser, userPO, activityInfo, record, taskInfo);
            //更新用户邀请记录 状态
            this.updateInviteStatus(record.getId());
            //TODO 有异议的方法 不知道干啥的
            this.updateUserInviteStatus(userParticipateActivityInfo, invitedByUser, userPO, activityInfo);
        } catch (Exception e) {
            log.error("updateInvitedByUser 异常:{}", e.getMessage(), e);
        }
    }

    /**
     * 创建 活动报名返回结果
     *
     * @param activityInfo
     * @param userParticipateActivityInfo
     * @return
     */
    private static ActivitySignUpRes getActivitySignUpRes(ActivityInfo activityInfo, UserParticipateActivityInfo userParticipateActivityInfo) {
        ActivitySignUpRes res = new ActivitySignUpRes();
        res.setHasQa(activityInfo.getHasQa());
        res.setDoQaHasCa(activityInfo.getDoQaHasCa());
        res.setCaName(userParticipateActivityInfo.getContestCaName());
        res.setPassed(userParticipateActivityInfo.getPassed());
        res.setScore(userParticipateActivityInfo.getQaScore());
        res.setActivityId(activityInfo.getId());
        res.setCsDetail(activityInfo.getAfterSignUpCsDetail());
        return res;
    }

    /**
     * 添加用户积分
     *
     * @param record
     * @param integral
     * @param desc
     * @param request
     * @param invite
     */
    private void addUserIntegral(String record, int integral, String desc, String request, String invite) {
        UserIntegralPO userIntegralPO1 = new UserIntegralPO();
        userIntegralPO1.setUserId(record);
        userIntegralPO1.setIntegral(integral);// 签到100积分
        userIntegralPO1.setDesc(desc);
        userIntegralPO1.setBizId(request);
        userIntegralPO1.setBizType(invite);
        userIntegralService.addIntegral(userIntegralPO1);
    }

    /**
     * 更新活动  日参与人数
     * 更新活动  时参与人数
     *
     * @param activityId
     * @param num
     */
    @Async
    public void updateActivityJoinNum(String activityId, Integer num) {
        try {
            Date now = new Date();
            //更新活动  日参与人数
            DayActivityJoinRecord dayActivityJoinRecord = new DayActivityJoinRecord();
            dayActivityJoinRecord.setActivityId(activityId);
            dayActivityJoinRecord.setNum(num);
            dayActivityJoinRecord.setTime(now);
            activityDataService.createDayActivityJoinRecord(dayActivityJoinRecord);
            //更新活动  时参与人数
            HourActivityJoinRecord hourActivityJoinRecord = new HourActivityJoinRecord();
            hourActivityJoinRecord.setActivityId(activityId);
            hourActivityJoinRecord.setNum(num);
            hourActivityJoinRecord.setTime(now);
            activityDataService.createHourActivityJoinRecord(hourActivityJoinRecord);
        } catch (Exception e) {
            log.error("更新活动参与人数错误", e);
        }

    }

    /**
     * 更新 承办单位相关
     *
     * @param activityId
     * @param userPO
     * @param platform
     * @param appId
     */
    private void updateOrganizer(String activityId, UserPO userPO, String platform, String appId) {
        log.info("updateOrganizer 开始更新承办单位榜单:{},{}", activityId, userPO.getId());
        // 更新承办单位邀请
        ActivityTaskInfo taskInfoOrg = activityTaskInfoService.findActivityTaskInfo(activityId, TaskBizType.ORGANIZER);
        if (Objects.isNull(taskInfoOrg)) {
            log.error("updateOrganizer 活动:{} 无线下志愿者活动", activityId);
            return;
        }
        // TODO:更新邀请状态
        UserInviteRecord record = this.getInvitedRecord(userPO.getId(), activityId, taskInfoOrg.getId());
        log.info("updateOrganizer 承办单位被邀请记录:{}", JSON.toJSONString(record));
        if (Objects.isNull(record) || StringUtils.isBlank(record.getInvitedByUserId())) {
            return;
        }
        //更新邀请记录 状态
        this.updateInviteStatus(record.getId());
        //获取 活动承办单位活动介绍
        ActivityOrganizerInfo organizerInfo = activityOrganizerInfoService.find(activityId, record.getInvitedByUserId());
        if (Objects.isNull(organizerInfo)) {
            log.info("updateOrganizer organizerInfo is null activityId:{},invitedByUserId:{}", activityId, record.getInvitedByUserId());
            return;
        }
        //获取 邀请人用户信息
        UserPO invitedByUser = visitorUserService.getUserUserId(platform, appId, record.getInvitedByUserId());
        if (Objects.isNull(invitedByUser)) {
            log.info("updateOrganizer invitedByUser is null invitedByUserId:{}", record.getInvitedByUserId());
            return;
        }
        // 更新承办单位活动榜单
        this.updateOrganizerRanking(invitedByUser, taskInfoOrg, organizerInfo);

    }

    /**
     * 更新承办单位榜单
     *
     * @param userPO
     * @param taskInfoOrg   组织 活动任务详情
     * @param organizerInfo
     */
    public void updateOrganizerRanking(final UserPO userPO,
                                       ActivityTaskInfo taskInfoOrg,
                                       ActivityOrganizerInfo organizerInfo) {
        Date date = new Date();
        Criteria criteria = Criteria.where("organizerId").is(organizerInfo.getId())
                .and("taskId").is(taskInfoOrg.getId())
                .and("activityId").is(taskInfoOrg.getActivityId());
        Query query = new Query();
        query.addCriteria(criteria);
        OrganizerRankingList ranking = mongoTemplate.findOne(query, OrganizerRankingList.class);
        if (Objects.isNull(ranking)) {
            ranking = new OrganizerRankingList();
            ranking.setActivityId(taskInfoOrg.getActivityId());
            ranking.setUserId(userPO.getId());
            ranking.setTaskId(taskInfoOrg.getId());
            ranking.setTaskBizType(TaskBizType.ORGANIZER);
            ranking.setCreatedTime(date);
            ranking.setUniversityName(userPO.getUniversityName());
            ranking.setImageUrl(organizerInfo.getLogoImageUrl());
            ranking.setName(organizerInfo.getOrgName());
            ranking.setQuantity(1.0D);
            ranking.setUniversityId(userPO.getUniversityId());
            ranking.setOrganizerId(organizerInfo.getId());
            ranking.setUniversityName(userPO.getUniversityName());
            ranking = mongoTemplate.insert(ranking);
            log.info("updateOrganizerRanking 新增 用户:{},任务榜单:{}", userPO.getId(), ranking.getId());
        } else {
            Query queryUpdate = new Query().addCriteria(Criteria.where("id").is(ranking.getId()));
            Update update = new Update();
            update.inc("quantity", 1.0D);
            update.set("updatedTime", date);
            UpdateResult result = mongoTemplate.updateFirst(queryUpdate, update, OrganizerRankingList.class);
            log.info("updateOrganizerRanking 更新 用户:{},任务榜单:{},结果数量为:{}", userPO.getId(), ranking.getId(), result.getModifiedCount());
        }
    }

    /**
     * 获取大学信息
     *
     * @param request
     * @return
     */
    private UniversityInfo getUniversityInfo(ActivitySignUpRequest request, boolean signUpInputUniversity) {
        if (signUpInputUniversity) {
            UniversityInfo saveUniversity = new UniversityInfo();
            saveUniversity.setName(request.getUniversityName());
            saveUniversity.setValue(request.getUniversityName());
            saveUniversity.setDataType(2);
            return universityService.saveOrUpdate(saveUniversity);
        } else {
            Query queryUni = new Query().addCriteria(Criteria.where("id").is(request.getUniversityId()));
            return mongoTemplate.findOne(queryUni, UniversityInfo.class);
        }
    }

    /**
     * 创建Feed 流
     *
     * @param activityId         活动id
     * @param activityTaskInfoId 活动任务详情 id
     * @param userPO             用户信息
     * @return
     */
    public boolean createActivityFeedInfo(String activityId, String activityTaskInfoId, UserPO userPO) {
        ActivityFeedInfo activityFeedInfo = new ActivityFeedInfo();
        activityFeedInfo.setActivityId(activityId);
        activityFeedInfo.setTaskInfoId(activityTaskInfoId);
        activityFeedInfo.setImageUr(userPO.getAvatarUrl());
        activityFeedInfo.setContent(userPO.getNickName() + "已报名");
        activityFeedInfo.setStatus(true);
        activityFeedInfo.setActivityStatus(2);
        Date date = new Date();
        activityFeedInfo.setCreatedTime(date);
        activityFeedInfo.setTtlDate(new Date(date.getTime() - 3600000L));
        log.info("createActivityFeedInfo 开始创建Feed 流:{}", JSON.toJSONString(activityFeedInfo));
        activityFeedInfo = mongoTemplate.insert(activityFeedInfo);
        //更新redis 缓存
        activityFeedInfoService.addActivityFeedInfo(activityFeedInfo.getActivityId(), activityFeedInfo.getActivityStatus(), activityFeedInfo);
        return true;
    }


    /**
     * 更新用户邀请报名状态 TODO 这里有疑问
     *
     * @param participateActivityInfo
     * @param invitedByUser
     * @param invitedToUser
     * @param activityInfo
     */
    public void updateUserInviteStatus(UserParticipateActivityInfo participateActivityInfo,
                                       UserPO invitedByUser,// 邀请人 用户信息
                                       UserPO invitedToUser, // 当前报名的用户
                                       ActivityInfo activityInfo) {
        log.info("updateUserInviteStatus 开始更新用户邀请报名状态: invitedByUser:{},activity:{}", JSON.toJSONString(invitedByUser), activityInfo.getId());
        this.platformOtherActivityService.updateUserInfo(invitedToUser, activityInfo.getId());
        //TODO 这里看不懂  答题错误 && 答题限制  就给答题次数 +1 什么逻辑
        if (!Boolean.TRUE.equals(participateActivityInfo.getPassed()) && Boolean.TRUE.equals(activityInfo.getQaLimit())) {
            int retryNum = participateActivityInfo.getReTryQaNum() == null ? 0 : participateActivityInfo.getReTryQaNum() + 1;
            participateActivityInfo.setReTryQaNum(retryNum);
            mongoTemplate.save(participateActivityInfo);
        }
    }

    private List<String> ACTIVITY_TYPE_LIST = Arrays.asList(
            "qq-mini-plus-noncontest",
            "qq-mini-plus",
            "h5++",
            "qq-mini-zhongqing-contest");

    /**
     * 更新排行榜 与 更新邀请人 贡献值
     *
     * @param invitedByUser 邀请人
     * @param invitedToUser 受邀人
     * @param activityInfo  活动信息
     * @param record        邀请记录
     * @param taskInfo      活动任务详情
     */
    private void updateInviteRank(UserPO invitedByUser,
                                  UserPO invitedToUser,
                                  ActivityInfo activityInfo,
                                  UserInviteRecord record,
                                  ActivityTaskInfo taskInfo) {
        String activityId = activityInfo.getId();
        String taskId = taskInfo.getId();
        if (!ACTIVITY_TYPE_LIST.contains(activityInfo.getType())) {
            //更新活动任务工作量
            this.updateTaskQuantity(record.getInvitedByUserId(), activityInfo.getId(), taskId, TaskBizType.INVITE, 1.0D);
            // 更新 邀请人贡献值榜单
            userActivityTaskRankingService.saveQuantityByInvited(invitedByUser, taskInfo, invitedToUser);
            // 更新周榜单
            this.updateUserTaskWeekRanking(invitedByUser, invitedToUser, taskInfo);
        } else {
            ActivityTaskRule rule = activityTaskRuleService.find(record.getActivityId(), TaskBizType.INVITE.name());
            String desc = "分享用户";
            //
            boolean limitInvite = false;
            UserParticipateActivityInfo up = userParticipateActivityInfoService.findByUserIdActivityId(invitedByUser.getId(), activityId);
            log.info("活动:{},邀请人:{} 报名时间:{}", activityId, invitedByUser.getId(), up == null ? null : up.getSignUpTime());
            if (Objects.nonNull(up) && Objects.nonNull(up.getSignUpTime()) && Objects.nonNull(taskInfo.getInviteLimit())) {
                if ((new Date().getTime() - up.getSignUpTime().getTime()) <= taskInfo.getInviteLimit() * 1000) {
                    limitInvite = true;
                }
            }
            if (limitInvite && Boolean.TRUE.equals(taskInfo.getHasInviteLimit())) {
                rule.setPoints(taskInfo.getInviteLimitQuantity());
                desc = "限时分享";
            } else {
                rule.setPoints(taskInfo.getPoints());
            }
            UserActivityPointDetail detail = new UserActivityPointDetail();
            detail.setActivityId(record.getActivityId());
            detail.setUserId(record.getInvitedByUserId());
            UserPO userPO = visitorUserService.getUser(record.getInvitedByUserId());
            detail.setUserPO(userPO);
            detail.setPoints(rule.getPoints().intValue());
            detail.setAction("add");
            detail.setBizDesc(desc);
            detail.setBizType("invite");
            userActivityPointDetailService.create(detail);
            // 更新省排行榜
            userActivityPointRankingProvinceService.updatePoint(userPO, record.getActivityId(), rule.getPoints().intValue());
        }
    }

    /**
     * 更新用户周榜单
     *
     * @param userPO
     * @param taskInfo
     */
    @Async
    public void updateUserTaskWeekRanking(final UserPO userPO, UserPO invitedToUser, ActivityTaskInfo taskInfo) {
        log.info(":>>> 开始更新用户周榜单用户:{},任务数据:{}", JSON.toJSONString(userPO), JSON.toJSONString(taskInfo));
        //增加的工作量
        //受邀人 学校id 与邀请人学校id 相同 增加 额外工作量
        Double quantity = taskInfo.getPoints();
        if (invitedToUser.getUniversityId().equals(userPO.getUniversityId())) {
            quantity = taskInfo.getPoints() + taskInfo.getExtraPoints();
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userPO.getId()).
                and("taskId").is(taskInfo.getId()).
                and("activityId").is(taskInfo.getActivityId())
                .and("taskBizType").is(TaskBizType.INVITE));

        Date startWeekTime = TimeUtils.getBeginDayOfWeek();
        Date endWeekTime = TimeUtils.getEndDayOfWeek();
        Criteria criteria = new Criteria()
                .andOperator(Criteria.where("weekTime").gte(TimeUtils.dateToISODate(startWeekTime)),
                        Criteria.where("weekTime").lte(TimeUtils.dateToISODate(endWeekTime)));
        query.addCriteria(criteria);
        UserWeekActivityTaskRanking ranking = mongoTemplate.findOne(query, UserWeekActivityTaskRanking.class);
        if (Objects.isNull(ranking)) {
            ranking = new UserWeekActivityTaskRanking();
            ranking.setActivityId(taskInfo.getActivityId());
            ranking.setUserId(userPO.getId());
            ranking.setTaskId(taskInfo.getId());
            ranking.setTaskBizType(TaskBizType.INVITE);
            ranking.setCreatedTime(new Date());
            ranking.setProvince(userPO.getProvince());
            ranking.setUniversityName(userPO.getUniversityName());
            ranking.setImageUrl(userPO.getAvatarUrl());
            ranking.setName(userPO.getNickName());
            ranking.setQuantity(quantity);
            // 时间设置为每周的第一天
            ranking.setWeekTime(startWeekTime);
            mongoTemplate.insert(ranking);

        } else {
            Query queryUpdate = new Query().addCriteria(Criteria.where("id").is(ranking.getId()));
            Update update = new Update();
            update.inc("quantity", quantity); // 累加
            update.set("updatedTime", new Date());
            UpdateResult result = mongoTemplate.updateFirst(queryUpdate, update, UserWeekActivityTaskRanking.class);
            log.info(":>>> 更新用户:{},任务周榜单:{},结果数量为:{}", userPO.getId(), ranking.getId(), result.getModifiedCount());
        }
    }

    /**
     * 更新活动任务工作量
     *
     * @param userId
     * @param activityId
     * @param taskId
     * @param num
     */
    private void updateTaskQuantity(final String userId,
                                    final String activityId,
                                    final String taskId,
                                    TaskBizType bizType,
                                    final Double num) {
        log.info("开始更新活动任务工作量:{},{},{},{}", userId, activityId, taskId, num);
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(activityId) || StringUtils.isBlank(taskId) || Objects.isNull(num) || Objects.isNull(bizType)) {
            log.error("更新活动任务参数错误:用户ID,活动ID,任务ID,数量为空,任务行动类型");
            return;
        }
        Criteria criteria = Criteria.where("userId").is(userId)
                .and("taskId").is(taskId)
                .and("activityId").is(activityId);
        Query query = new Query();
        query.addCriteria(criteria);
        UserParticipateActivityTaskInfo taskInfo = mongoTemplate.findOne(query, UserParticipateActivityTaskInfo.class);
        if (Objects.isNull(taskInfo)) {
            log.info("用户:{} ,参与活动:{},任务:{},业务:{} 不存在，开始创建", userId, activityId, taskId, bizType);
            taskInfo = new UserParticipateActivityTaskInfo();
            taskInfo.setActivityId(activityId);
            taskInfo.setBizType(bizType);
            taskInfo.setTaskId(taskId);
            taskInfo.setUserId(userId);
            taskInfo.setCreatedTime(new Date());
            taskInfo.setQuantity(num);
            // 开始1等级
            taskInfo.setStep(1);
            mongoTemplate.insert(taskInfo);
        } else {
            Query queryUpdate = new Query().addCriteria(Criteria.where("id").is(taskInfo.getId()));
            Update update = new Update();
            update.inc("quantity", num);
            mongoTemplate.updateFirst(queryUpdate, update, UserParticipateActivityTaskInfo.class);
        }

    }


    /**
     * 更新用户邀请状态
     *
     * @param id
     */
    private void updateInviteStatus(String id) {
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        Date now = new Date();
        update.set("joinStatus", true);
        update.set("updatedTime", now);
        update.set("joinTime", now);
        UpdateResult result = mongoTemplate.updateFirst(query, update, UserInviteRecord.class);
        log.info("更新:{} 被邀请,记录结果:{}", id, result.getModifiedCount() > 0 ? true : false);
    }

    /**
     * 获取用户被邀请记录:一个活动的任务用户只能被邀请一次
     *
     * @param userId
     * @param activityId
     * @param taskId
     * @return
     */
    private UserInviteRecord getInvitedRecord(String userId, String activityId, String taskId) {
        Query query = new Query().addCriteria(Criteria.where("invitedToUserId").is(userId).and("activityId").is(activityId).and("taskId").is(taskId));
        UserInviteRecord userInviteRecord = masterMongoTemplate.findOne(query, UserInviteRecord.class);
        return userInviteRecord;
    }

    /**
     * 更新高校总榜单
     *
     * @param userPO
     * @param activityId
     */
    private void updateUniversityTaskAllRanking(UserPO userPO, String activityId) {
        try {
            universityActivityRankingService.updateQuantity(userPO, activityId, userPO.getUniversityId(), 1);
            log.info("updateUniversityTaskAllRanking 更新大学:{},任务榜单:{},结果数量为:{}", userPO.getUniversityId());
        } catch (Exception e) {
            log.error("updateUniversityTaskAllRanking修改大学榜单信息 error:{}", e);
        }
    }

    /**
     * 更新活动用户统计
     *
     * @param activityId
     * @param createUserTime
     * @param activityStartTime
     */
    private void updateActivityUserStatistics(String activityId, Date createUserTime, Date activityStartTime) {
        log.info("updateActivityUserStatistics activityId:{}", activityId);
        try {
            //查询活动 用户 统计
            ActivityUserStatistics statistics = activityUserStatisticsService.findByActivityId(activityId);
            if (Objects.isNull(statistics)) {
                statistics = new ActivityUserStatistics();
                statistics.setActivityId(activityId);
                statistics.setNewUserCount(0);
                statistics.setOldUserCount(0);
            }
            //如果 用户创建时间在活动开始时间之后，则新用户
            if (createUserTime.after(activityStartTime)) {
                statistics.setNewUserCount(statistics.getNewUserCount() + 1);
            } else {
                statistics.setOldUserCount(statistics.getOldUserCount() + 1);
            }
            activityUserStatisticsService.save(statistics);
        } catch (Exception e) {
            log.error("updateActivityUserStatistics 更新用户数量错误:{}", e.getMessage(), e);
        }
    }

    /**
     * 更新用户信息
     *
     * @param request
     * @param userPO
     */
    private void updateUserInfo(ActivitySignUpRequest request, UserPO userPO, UniversityInfo universityInfo) {
        // 更新用户信息
        UserPO updateUser = new UserPO();
        updateUser.setId(userPO.getId());
        updateUser.setName(request.getName());
        updateUser.setMobile(request.getMobile());
        updateUser.setQqNumber(request.getQq());
        updateUser.setUniversityId(universityInfo.getId());
        updateUser.setUniversityName(universityInfo.getName());
        updateUser.setUniversityLogo(universityInfo.getLogo());
        updateUser.setProvince(universityInfo.getProvince());
        updateUser.setCity(universityInfo.getCity());
        updateUser.setFullAddress(request.getFullAddress());
        log.info("updateUserInfo updateUser:{}", JSON.toJSONString(updateUser));
        visitorUserService.updateUser(updateUser);

        //更新用户扩展信息
        userPO.setUniversityId(universityInfo.getId());
        userPO.setUniversityName(universityInfo.getName());
        userPO.setUniversityLogo(universityInfo.getLogo());
        userPO.setProvince(universityInfo.getProvince());
        userPO.setCity(universityInfo.getCity());
        userPO.setMobile(request.getMobile());
        userPO.setName(request.getName());
        userPO.setH5SignUp(Boolean.TRUE);
        log.info("updateUserInfo userPO:{}", JSON.toJSONString(userPO));
        userInfoExtendService.saveOrUpdate(userPO);
    }

    /**
     * 更新 用户参与活动用户
     *
     * @param up
     * @param request
     * @param userPO
     * @param activityInfo
     * @return
     */
    private UserParticipateActivityInfo saveUserParticipateActivityInfo(UserParticipateActivityInfo up, ActivitySignUpRequest request, UserPO userPO, ActivityInfo activityInfo) {
        Date now = new Date();
        if (Objects.isNull(up)) {
            up = new UserParticipateActivityInfo();
            up.setCreatedTime(now);
            up.setReTryQaNum(activityInfo.getReTryQaNum());
        }
        up.setActivityId(request.getActivityId());
        up.setUserId(request.getUserId());
        up.setJoined(true);//已报名
        up.setName(request.getName());
        up.setMobile(request.getMobile());
        up.setQq(request.getQq());
        up.setUniversityId(request.getUniversityId());
        up.setStatus("1");
        up.setGrade(request.getGrade());
        up.setCurrentStep(0);
        //用户信息
        up.setOpenId(userPO.getOpenId());
        up.setUnionId(userPO.getUnionId());
        up.setAppId(userPO.getAppId());
        up.setPlatform(userPO.getCurrentPlatform());
        up.setUniversityName(request.getUniversityName());
        up.setSignUpTime(now);
        up.setUpdatedTime(now);
        up = mongoTemplate.save(up);
        log.info("saveUserParticipateActivityInfo 添加报名记录成功 up:{}", JSON.toJSONString(up));
        return up;
    }

    @Override
    public boolean updateSignUpInfo(ActivitySignUpRequest activitySignUpRequest) {
        log.info(":>>> 开始修改报名信息:{}", JSON.toJSONString(activitySignUpRequest));
        if (StringUtils.isAnyBlank(activitySignUpRequest.getUserId(), activitySignUpRequest.getActivityId())) {
            log.error(":>>> 修改报名信息参数错误:活动ID或手机号为空");
            throw new BusinessException("修改报名信息参数错误:活动ID或手机号为空");
        }
        List<String> uids = visitorUserService.findCorrentUserId(activitySignUpRequest.getUserId());
        UserParticipateActivityInfo up = userParticipateActivityInfoService.findBy(activitySignUpRequest.getActivityId(), activitySignUpRequest.getUserId(), uids);
        if (Objects.isNull(up)) {
            log.error(":>>>  用户:{} 未参加活动:{}", activitySignUpRequest.getUserId(), activitySignUpRequest.getActivityId());
            throw new BusinessException("用户未参加活动");
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(up.getMobile()).and("activityId").is(activitySignUpRequest.getActivityId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(activitySignUpRequest.getMobile()) && !up.getMobile().equals(activitySignUpRequest.getMobile())) {
            update.set("mobile", activitySignUpRequest.getMobile());
        }
        if (StringUtils.isNotBlank(activitySignUpRequest.getName()) && !up.getName().equals(activitySignUpRequest.getName())) {
            update.set("name", activitySignUpRequest.getName());
        }
        if (StringUtils.isNotBlank(activitySignUpRequest.getGrade()) && !up.getGrade().equals(activitySignUpRequest.getGrade())) {
            update.set("grade", activitySignUpRequest.getGrade());
        }
        if (StringUtils.isNotBlank(activitySignUpRequest.getQq()) && !up.getQq().equals(activitySignUpRequest.getQq())) {
            update.set("qq", activitySignUpRequest.getGrade());
        }
        boolean updateUniversity = false;
        if (StringUtils.isNotBlank(activitySignUpRequest.getUniversityId()) && !up.getUniversityId().equals(activitySignUpRequest.getUniversityId())) {
            update.set("universityId", activitySignUpRequest.getUniversityId());
            UniversityInfo universityInfo = universityService.get(activitySignUpRequest.getUniversityId());
            if (Objects.isNull(universityInfo)) {
                throw new BusinessException("学校信息获取失败,请稍后重试");
            }
            update.set("universityName", universityInfo.getName());
            update.set("province", universityInfo.getProvince());
            updateUniversity = true;
        }
        update.set("updatedTime", new Date());
        UpdateResult updateResult = mongoTemplate.updateMulti(query, update, UserParticipateActivityInfo.class);
        if (updateResult.getModifiedCount() <= 0) {
            return false;
        }
        //发生学校变更 减 额外贡献值
        if (updateUniversity) {
            subtractEextraPoints(activitySignUpRequest, up);
        }
        return true;
    }

    /**
     * 扣减 额外贡献值数量
     *
     * @param activitySignUpRequest
     * @param up
     */
    private void subtractEextraPoints(ActivitySignUpRequest activitySignUpRequest, UserParticipateActivityInfo up) {
        try {
            //查询 用户 额外贡献值记录
            String activityId = activitySignUpRequest.getActivityId();
            List<UserActivityQuantityRecord> recordList = userActivityQuantityRecordService.findByInviteToUserIdAndActivityIdAndExtraPointsStatus(up.getUserId(), activityId, false);
            if (CollectionUtils.isEmpty(recordList)) {
                return;
            }
            recordList = recordList.stream().filter(record -> record.getExtraPoints() > 0).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(recordList)) {
                return;
            }
            Map<String, Double> subtractEextraPointsMap = recordList.stream().collect(Collectors.toMap(
                    record -> record.getUserId(),
                    record -> record.getExtraPoints(),
                    (old, newRecord) -> old + newRecord
            ));

            //减贡献值
            for (Map.Entry<String, Double> entry : subtractEextraPointsMap.entrySet()) {
                String userId = entry.getKey();
                Double quantity = -entry.getValue();
                // 更新 用户 贡献值榜单
                userActivityTaskRankingService.addQuantityByUserIdAndActivityId(userId, activityId, quantity, TaskBizType.UPDATE_UNIVERSITY);
            }
            //贡献值 额外贡献值 设置为失效
            for (UserActivityQuantityRecord record : recordList) {
                record.setExtraPointsStatus(true);
            }
            userActivityQuantityRecordService.batchUpdate(recordList);
        } catch (Exception e) {
            log.error("subtract 扣减用户贡献值错误:{}", e.getMessage(), e);
        }

    }

}
